/*+***********************************************************************************
 Filename: A01_tinyriscv_mcu01\src\top.v
 Description: porting tinyriscv to tangnano9k, using DualPort RAM.
   a mcu framework with 32k rom, 16k ram. 
   JTAG access rom, ram and peripheral through bus arbiter.
   Core access rom and ram directly, and access peripheral through bus arbiter.

 Modification:
   2023.12.23 Creation   H.Zheng
   2024.01.07 modify jtag clk
   2024.02.05 copy and modified from A01_tinyriscv_step02   H.Zheng
              remove rom2
   2024.02.06 modify mux_2x3, change rom to 32k
   2024.02.07 change ram&rom clk to ~core_clk
   2024.02.08 peripheral add clk_1MHz, int_flag
Copyright (C) 2024  Zheng Hui (hzheng@gzhu.edu.cn)

License: MulanPSL-2.0

***********************************************************************************-*/

`include "./core/defines.v"

module top
(
    input wire [1:0] button,
    input wire sys_clk,
    output wire [5:0] led,
    input wire uart0_rxd,
    output wire uart0_txd,
    input wire jtag_TCK,
    input wire jtag_TMS,
    input wire jtag_TDI,
    output wire jtag_TDO
);
    //PLL
    wire clk_108MHz;
    Gowin_rPLL m_pll(
        .clkout(clk_108MHz), //output clkout
        .clkin(sys_clk) //input clkin
    );

    //
    wire reset_n = button[1];
    wire jtag_reset_n = button[0];

    //core clk
    reg [26:0] counter;

    always @(posedge clk_108MHz) begin
        counter <= counter + 1'b1;
    end

//    wire core_clk = counter[0]; //54MHz  //not work
    wire core_clk = counter[1]; //27MHz
//    wire core_clk = counter[3]; //6.25MHz
//    wire core_clk = counter[2]; //13.5MHz
//    wire core_clk = counter[26]; //1Hz

//
    //jtag clk
    reg [5:0] jtagclk_counter;
    reg clk_1MHz;

    always @(posedge clk_108MHz) begin
        if (jtagclk_counter >=6'd53) begin
            jtagclk_counter <= 0;
            clk_1MHz <= ~clk_1MHz;
        end
        else begin
            jtagclk_counter <= jtagclk_counter + 1'b1;
        end
    end

    //jtag port
    wire jtag_halt_req_o;
    wire jtag_reset_req_o;
    wire[`RegAddrBus] jtag_reg_addr_o;
    wire[`RegBus] jtag_reg_data_o;
    wire jtag_reg_we_o;
    wire[`RegBus] jtag_reg_data_i;
	  wire jtag_mem_we_o;
    wire [31:0] jtag_mem_addr_o;    
    wire [31:0] jtag_mem_data_i;
    wire [31:0] jtag_mem_data_o;
    wire jtag_debug_req;

    // tinyriscv port
//    wire[`INT_BUS] int_flag = `INT_NONE;
    wire[`INT_BUS] int_flag;
//    wire rib_hold_flag_o = `Hold_None;
    wire rib_hold_flag_o;

    wire [31:0] ibus_addr;
    wire [31:0] instruction;
    wire [31:0] core_loadstore_addr;
    wire [31:0] core_loadstore_data_in;
    wire [31:0] core_loadstore_data_out;
    wire core_loadstore_ce;
    wire core_loadstore_we;



    // tinyriscv处理器核模块例化
    tinyriscv u_tinyriscv(
        .clk(core_clk),
        .rst(reset_n),
        .rib_ex_addr_o(core_loadstore_addr),
        .rib_ex_data_i(core_loadstore_data_in),
        .rib_ex_data_o(core_loadstore_data_out),
        .rib_ex_req_o(core_loadstore_ce),
        .rib_ex_we_o(core_loadstore_we),

        .rib_pc_addr_o(ibus_addr),
        .rib_pc_data_i(instruction),

        .jtag_reg_addr_i(jtag_reg_addr_o),
        .jtag_reg_data_i(jtag_reg_data_o),
        .jtag_reg_we_i(jtag_reg_we_o),
        .jtag_reg_data_o(jtag_reg_data_i),

        .rib_hold_flag_i(rib_hold_flag_o),
        .jtag_halt_flag_i(jtag_halt_req_o),
        .jtag_reset_flag_i(jtag_reset_req_o),

        .int_i(int_flag)
    );


    // jtag模块例化
    jtag_top #(
        .DMI_ADDR_BITS(6),
        .DMI_DATA_BITS(32),
        .DMI_OP_BITS(2)
    ) u_jtag_top(
        .clk(clk_1MHz),
        .jtag_rst_n(jtag_reset_n),
        .jtag_pin_TCK(jtag_TCK),
        .jtag_pin_TMS(jtag_TMS),
        .jtag_pin_TDI(jtag_TDI),
        .jtag_pin_TDO(jtag_TDO),
        .reg_we_o(jtag_reg_we_o),
        .reg_addr_o(jtag_reg_addr_o),
        .reg_wdata_o(jtag_reg_data_o),
        .reg_rdata_i(jtag_reg_data_i),
        .mem_we_o(jtag_mem_we_o),
        .mem_addr_o(jtag_mem_addr_o),
        .mem_wdata_o(jtag_mem_data_o),
        .mem_rdata_i(jtag_mem_data_i),
        .op_req_o(jtag_debug_req),
        .halt_req_o(jtag_halt_req_o),
        .reset_req_o(jtag_reset_req_o)
    );

//Memory part

//rom address in bytes = [0x0???0000-0x0???7fff]: 32kBytes
//ram address in bytes  = [0x2???0000-0x2???3fff]: 16kBytes
//peripheral address    = [0x1???0000-0x1???3fff]: 16kBytes

//core side
    wire rom_ce;
    wire [31:0] rom_instruction;
    assign rom_ce = (ibus_addr[31:28] == 4'd0) & (ibus_addr[15:14] == 2'b00);
    assign instruction = rom_ce ? rom_instruction : 32'b0;

    wire [31:0] ram_data_out;
    wire [31:0] peripheral_data_out;
    wire ram_ce;
    wire peripheral_ce;
    assign ram_ce  = (core_loadstore_addr[31:28] == 4'd2) & (core_loadstore_addr[15:14] == 2'b00) & core_loadstore_ce;
    assign peripheral_ce  = (core_loadstore_addr[31:28] == 4'd1) & (core_loadstore_addr[15:14] == 2'b00) & core_loadstore_ce;
    assign core_loadstore_data_in = (ram_ce) ? ram_data_out :
                                 (peripheral_ce) ? peripheral_data_out : 32'b0;

//JTAG side

    //bus mux

    wire[31:0] d0_addr_o, d1_addr_o, d2_addr_o;
    wire[31:0] d0_data_o, d1_data_o, d2_data_o;
    wire[31:0] d0_data_i, d1_data_i, d2_data_i;

//   wire h1_req_i = peripheral_ce & (~jtag_halt_req_o); //when in halt mode, h1_req_i is invalid

    mux_2x3 u_mux(
        // host 0 interface
        .h0_addr_i(jtag_mem_addr_o),
        .h0_data_i(jtag_mem_data_o),
        .h0_data_o(jtag_mem_data_i),
        .h0_req_i(jtag_debug_req),
        .h0_we_i(jtag_mem_we_o),

        // host 1 interface: connect to core's load-store bus sub2
        .h1_addr_i(core_loadstore_addr),
        .h1_data_i(core_loadstore_data_out),
        .h1_data_o(peripheral_data_out),
        .h1_req_i(peripheral_ce),
//        .h1_req_i(h1_req_i),
        .h1_we_i(core_loadstore_we),

        // device 0 interface: to rom
        .d0_addr_o(d0_addr_o),
        .d0_data_o(d0_data_o),
        .d0_data_i(d0_data_i),
        .d0_we_o(d0_we_o),
        .d0_ce_o(d0_ce_o),

        // device 1 interface: to peripheral
        .d1_addr_o(d1_addr_o),
        .d1_data_o(d1_data_o),
        .d1_data_i(d1_data_i),
        .d1_we_o(d1_we_o),
        .d1_ce_o(d1_ce_o),

        // device 2 interface: to ram
        .d2_addr_o(d2_addr_o),
        .d2_data_o(d2_data_o),
        .d2_data_i(d2_data_i),
        .d2_we_o(d2_we_o),
        .d2_ce_o(d2_ce_o),

        //core hold flag
        .h1_hold_flag_o(rib_hold_flag_o)
//        .h1_hold_flag_o()
    );

    // rom模块例化
    Gowin_DPB_32K I_ROM(
        .clka(clk_108MHz), //input clka
        .ocea(1'b1), //input ocea
        .reseta(~jtag_reset_n), //input reseta
        .cea(d0_ce_o), //input cea
        .wrea(d0_we_o), //input wrea
        .ada(d0_addr_o[14:2]), //input [12:0] ada
        .douta(d0_data_i), //output [31:0] douta
        .dina(d0_data_o), //input [31:0] dina

//        .clkb(clk_108MHz), //input clkb
        .clkb(~core_clk), //input clkb
        .oceb(1'b1), //input oceb
        .ceb(rom_ce), //input ceb
        .resetb(~reset_n), //input resetb
        .wreb(1'b0), //input wreb
        .adb(ibus_addr[14:2]), //input [12:0] adb
        .doutb(rom_instruction), //output [31:0] doutb
        .dinb(32'b0) //input [31:0] dinb
    );  

    // ram模块例化
    Gowin_DPB D_RAM(
        .clka(clk_108MHz), //input clka
        .reseta(~jtag_reset_n), //input reseta
        .ocea(1'b1), //input ocea
        .cea(d2_ce_o), //input cea
        .wrea(d2_we_o), //input wrea
        .ada(d2_addr_o[13:2]), //input [11:0] ada
        .douta(d2_data_i), //output [31:0] douta
        .dina(d2_data_o), //input [31:0] dina

        .clkb(~core_clk), //input clkb
        .oceb(1'b1), //input oceb
        .ceb(ram_ce), //input ceb
        .resetb(~reset_n), //input resetb
        .wreb(core_loadstore_we), //input wreb
        .adb(core_loadstore_addr[13:2]), //input [11:0] adb
        .doutb(ram_data_out), //output [31:0] doutb
        .dinb(core_loadstore_data_out) //input [31:0] dinb
    );  


    //peripherals
    wire [5:0] peri_led;
    wire peri_txd;    

    peripheral m_peripheral(
        .clk(~core_clk),
        .clk_1MHz(clk_1MHz),
        .reset_n(reset_n),
        .button(button[0]),
        .led(peri_led),
        .rxd(uart0_rxd),
        .txd(uart0_txd),
        //
        .ce(d1_ce_o),
        .wre(d1_we_o),
        .addr(d1_addr_o[13:2]),
        .data_in(d1_data_o),
        .data_out(d1_data_i),
        //
        .int_flag(int_flag)
    );


    //output
    assign led = peri_led; 
//    assign led = {~ibus_addr[7:4], peri_led[1:0]}; 
//    assign led = ~ibus_addr[7:2];
//    assign led = ~{ibus_addr[3:2], rom1_instruction[3:0]};
//    assign led = ~{ibus_addr[3:2], rom1_instruction[7:4]};


endmodule